package com.keitaitoys.fonteditor.core;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.Properties;

import com.keitaitoys.fonteditor.FontEditor;

public class PropertiesManager {

	//////////////////////////////////////////////////////////////////////
	// Description ///////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////
	// Consts ////////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////

	private static final String DEFAULT_PROPERTIES_FILE_NAME = "default.properties";
	private static final String USER_PROPERTIES_FILE_NAME = "user.properties";
	
	private static final String GENERATED_PROPERTIES_COMMENT = "Self-generated by application on";
	private static final String MODIFIED_PROPERTIES_COMMENT = "Modified by application on";
	
	//////////////////////////////////////////////////////////////////////
	// Variables /////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////

	private static PropertiesManager manager;

	private Properties defaultProperties;
	private Properties properties;
	
	//////////////////////////////////////////////////////////////////////
	// Constructor ///////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////

	private PropertiesManager() throws PropertiesLoadFailedException {
		
		// Загружаем настройки
		load();
	}
	
	//////////////////////////////////////////////////////////////////////
	// Functions ///////////////////////////////////////////////////////// 
	//////////////////////////////////////////////////////////////////////
	
	public static synchronized PropertiesManager getInstance() {
		
		if(manager == null) {
			
			try {
				manager = new PropertiesManager();
			} catch(PropertiesLoadFailedException e) {}
		}
		
		return manager;
	}

	//////////////////////////////////////////////////////////////////////
	// Functions ///////////////////////////////////////////////////////// 
	//////////////////////////////////////////////////////////////////////

	public void load() throws PropertiesLoadFailedException {
		
		loadProperties();
	}

	//////////////////////////////////////////////////////////////////////
	// Functions ///////////////////////////////////////////////////////// 
	//////////////////////////////////////////////////////////////////////

	private synchronized void loadProperties() throws PropertiesLoadFailedException {
		
		// Создаем настройки по умолчанию
		Properties defaultProperties = new Properties();
		
		String defaultPropertiesFileName = DEFAULT_PROPERTIES_FILE_NAME;
		File defaultPropertiesFile = new File(defaultPropertiesFileName);

		if(defaultPropertiesFile == null || !defaultPropertiesFile.exists()) {

			if(FontEditor.DEBUG) {
				System.out.println("File \"" + defaultPropertiesFile.getName() + "\" not found");
			}

			try {
				
				// Cоздаем файл настроек по умолчанию
				createDefaultProperties();
				
			} catch(PropertiesCreateFailedException e) {
				
				if(FontEditor.DEBUG) {
					System.out.println("Failed to create default properties file!");
					e.printStackTrace();
				}

				throw new PropertiesLoadFailedException(e);
			}
		}

		Reader defaultPropertiesReader = null;
		
		try {

			// Подгружаем настройки по умолчанию
			defaultPropertiesReader = new BufferedReader(new FileReader(defaultPropertiesFile));
			defaultProperties.load(defaultPropertiesReader);

		} catch(IOException e) {

			if(FontEditor.DEBUG) {
				System.out.println("Failed to load default properties!");
				e.printStackTrace();
			}
			
			throw new PropertiesLoadFailedException(e);

		} finally {

			if(defaultPropertiesReader != null) {

				try {
					defaultPropertiesReader.close();
				} catch(IOException e) {
					
					if(FontEditor.DEBUG) {
						System.out.println("Can't close file input stream");
					}
				}
			}
		}

		// Создаем настройки пользователя
		Properties properties = new Properties(defaultProperties);

		String userPropertiesFileName = USER_PROPERTIES_FILE_NAME;
		File userPropertiesFile = new File(userPropertiesFileName);

		if(userPropertiesFile == null || !userPropertiesFile.exists()) {
			
			if(FontEditor.DEBUG) {
				System.out.println("File \"" + userPropertiesFile.getName() + "\" not found");
			}

			try {
				
				// Пытаемся создать файл настроек пользователя
				createUserProperties();

			} catch(PropertiesCreateFailedException e) {
				
				if(FontEditor.DEBUG) {
					System.out.println("Failed to create user properties file!");
					e.printStackTrace();
				}

				throw new PropertiesLoadFailedException(e);
			}
		}

		Reader userPropertiesReader = null;

		try {
		
			// Подгружаем настройки пользователя
			userPropertiesReader = new BufferedReader(new FileReader(userPropertiesFile)); 
			properties.load(userPropertiesReader);
			
		} catch(IOException e) {

			if(FontEditor.DEBUG) {
				System.out.println("Failed to load user properties!");
				e.printStackTrace();
			}
			
			throw new PropertiesLoadFailedException(e);

		} finally {
			
			if(userPropertiesReader != null) {

				try {
					userPropertiesReader.close();
				} catch(IOException e) {
					
					if(FontEditor.DEBUG) {
						System.out.println("Can't close file input stream");
					}
				}
			}
		}

		this.defaultProperties = defaultProperties;
		this.properties = properties;
	}

	//////////////////////////////////////////////////////////////////////
	// Functions ///////////////////////////////////////////////////////// 
	//////////////////////////////////////////////////////////////////////

	public void save() throws PropertiesSaveFailedException {
		
		saveUserProperties();
	}

	//////////////////////////////////////////////////////////////////////
	// Functions ///////////////////////////////////////////////////////// 
	//////////////////////////////////////////////////////////////////////

	public synchronized void saveDefaultProperties() throws PropertiesSaveFailedException {
		
		File propertiesFile = new File(DEFAULT_PROPERTIES_FILE_NAME);
		Writer writer = null;
		
		try {

			writer = new BufferedWriter(new FileWriter(propertiesFile));
			defaultProperties.store(writer, MODIFIED_PROPERTIES_COMMENT);
		
		} catch(IOException e) {
			
			if(FontEditor.DEBUG) {
				System.out.println("Failed to save default properties!");
			}
			
			throw new PropertiesSaveFailedException(e);

		} finally {
			
			if(writer != null) {

				try {
					 writer.close();
				} catch(IOException e) {
					
					if(FontEditor.DEBUG) {
						System.out.println("Can't close file output stream");
					}
				}
			}
		}
	}

	//////////////////////////////////////////////////////////////////////
	// Functions ///////////////////////////////////////////////////////// 
	//////////////////////////////////////////////////////////////////////

	public synchronized void saveUserProperties() throws PropertiesSaveFailedException {
		
		File propertiesFile = new File(USER_PROPERTIES_FILE_NAME);
		Writer writer = null;
		
		try {

			writer = new BufferedWriter(new FileWriter(propertiesFile));
			properties.store(writer, USER_PROPERTIES_FILE_NAME);
		
		} catch(IOException e) {
			
			if(FontEditor.DEBUG) {
				System.out.println("Failed to save user properties!");
			}
			
			throw new PropertiesSaveFailedException(e);

		} finally {
			
			if(writer != null) {

				try {
					 writer.close();
				} catch(IOException e) {
					
					if(FontEditor.DEBUG) {
						System.out.println("Can't close file output stream");
					}
				}
			}
		}
	}

	//////////////////////////////////////////////////////////////////////
	// Functions ///////////////////////////////////////////////////////// 
	//////////////////////////////////////////////////////////////////////

	private synchronized void createDefaultProperties() throws PropertiesCreateFailedException {
		
		Properties properties = new Properties();
		
		// # Directories
		properties.put("locale.directory", LocaleManager.LOCALE_DIRECTORY);
		properties.put("plugin.directory", PluginManager.PLUGIN_DIRECTORY);
		
		File propertiesFile = new File(DEFAULT_PROPERTIES_FILE_NAME);
		Writer writer = null;
		
		try {

			writer = new BufferedWriter(new FileWriter(propertiesFile));
			properties.store(writer, GENERATED_PROPERTIES_COMMENT);
			
			writer.flush();
		
		} catch(IOException e) {
			
			if(FontEditor.DEBUG) {
				System.out.println("Can't create \"" + propertiesFile.getName() + "\" file");
			}
			
			throw new PropertiesCreateFailedException(e);

		} finally {
			
			if(writer != null) {

				try {
					 writer.close();
				} catch(IOException e) {
					
					if(FontEditor.DEBUG) {
						System.out.println("Can't close file output stream");
					}
				}
			}
		}
	}

	//////////////////////////////////////////////////////////////////////
	// Functions ///////////////////////////////////////////////////////// 
	//////////////////////////////////////////////////////////////////////

	private synchronized void createUserProperties() throws PropertiesCreateFailedException {
		
		Properties properties = new Properties();
		
		// # Locale
		properties.put("locale.language", "");
		properties.put("locale.country", "");
		properties.put("locale.variant", "");

		// # Preferences
		properties.put("editor.grid", "");
		properties.put("editor.bounds", "");
		properties.put("editor.color.bounds.red", "");
		properties.put("editor.color.bounds.green", "");
		properties.put("editor.color.bounds.blue", "");
		properties.put("editor.color.background.major.red", "");
		properties.put("editor.color.background.major.green", "");
		properties.put("editor.color.background.major.blue", "");
		properties.put("editor.color.background.minor.red", "");
		properties.put("editor.color.background.minor.green", "");
		properties.put("editor.color.background.minor.blue", "");
		properties.put("preview.mode", "");
		properties.put("preview.color.background.red", "");
		properties.put("preview.color.background.green", "");
		properties.put("preview.color.background.blue", "");

		// # Look & Feel
		properties.put("lookandfeel.name", "");
		properties.put("lookandfeel.class", "");
		
		// # Filechooser
		properties.put("filechooser.fontopen.directory", "");
		properties.put("filechooser.fontsave.directory", "");
		properties.put("filechooser.fontexport.directory", "");
		properties.put("filechooser.imageopen.directory", "");

		File propertiesFile = new File(USER_PROPERTIES_FILE_NAME);
		Writer writer = null;
		
		try {

			writer = new BufferedWriter(new FileWriter(propertiesFile));
			properties.store(writer, GENERATED_PROPERTIES_COMMENT);
			
			writer.flush();
		
		} catch(IOException e) {
			
			if(FontEditor.DEBUG) {
				System.out.println("Can't create \"" + propertiesFile.getName() + "\" file");
			}
			
			throw new PropertiesCreateFailedException(e);

		} finally {
			
			if(writer != null) {

				try {
					 writer.close();
				} catch(IOException e) {
					
					if(FontEditor.DEBUG) {
						System.out.println("Can't close file output stream");
					}
				}
			}
		}
	}

	//////////////////////////////////////////////////////////////////////
	// Functions ///////////////////////////////////////////////////////// 
	//////////////////////////////////////////////////////////////////////

	public String getProperty(String key) {
		
		return properties.getProperty(key);
	}

	//////////////////////////////////////////////////////////////////////
	// Functions ///////////////////////////////////////////////////////// 
	//////////////////////////////////////////////////////////////////////

	public String getProperty(String key, String defaultValue) {
		
		return properties.getProperty(key, defaultValue);
	}

	//////////////////////////////////////////////////////////////////////
	// Functions ///////////////////////////////////////////////////////// 
	//////////////////////////////////////////////////////////////////////

	public int getInt(String key) {
		
		int value = 0;
		
		try {
			value = Integer.parseInt(properties.getProperty(key));
		} catch(NumberFormatException e) {}
		
		return value;
	}

	//////////////////////////////////////////////////////////////////////
	// Functions ///////////////////////////////////////////////////////// 
	//////////////////////////////////////////////////////////////////////

	public int getInt(String key, int defaultValue) {
		
		int value = defaultValue;
		
		try {
			value = Integer.parseInt(properties.getProperty(key));
		} catch(NumberFormatException e) {}
		
		return value;
	}

	//////////////////////////////////////////////////////////////////////
	// Functions ///////////////////////////////////////////////////////// 
	//////////////////////////////////////////////////////////////////////

	public int getInteger(String key, int minValue, int maxValue, int defaultValue) {
		
		int value = defaultValue;
		
		try {
			value = Integer.parseInt(properties.getProperty(key));
		} catch(NumberFormatException e) {}
		
		if(value < minValue || value > maxValue) value = defaultValue;
		
		return value;
	}

	//////////////////////////////////////////////////////////////////////
	// Functions ///////////////////////////////////////////////////////// 
	//////////////////////////////////////////////////////////////////////

	public boolean getBoolean(String key, boolean defaultValue) {
		
		boolean value = defaultValue;
		
		String property = properties.getProperty(key);
		
		if(property != null && property.length() > 0) {
			value = Boolean.valueOf(property);
		}
		
		return value;
	}

	//////////////////////////////////////////////////////////////////////
	// Functions ///////////////////////////////////////////////////////// 
	//////////////////////////////////////////////////////////////////////

	public void setProperty(String key, String value) {
		
		properties.put(key, value);
	}
}
